# -*- coding: utf-8 -*-
"""
Created on Sat Oct 06 11:49:18 2012

@author: Tomek
"""

import namespace
ns=namespace.loadNamespace("__ns__data__")
export=[]
usingNamespace=[]
#desc export
#[0]==name
#[1]==template data
#[1][x][0]==templates
#[1][x][1]==template name
globalTab=""
def readExportObjects():
    global export
    f=open("export.txt","r")
    for x in f.readlines():
        data=x.split("|")
        if(len(data)==2):
            data[1]=data[1].split(";")
            for t in range(0,len(data[1])):
                data[1][t]=data[1][t].split("=")
            export.append(data)
def readUsingNamespace():
    global usingNamespace
    f=open("usingNs.txt","r")
    for x in f.readlines():
        usingNamespace.append(x)
def isUsingNamespace(x):
    for y in usingNamespace:
        if x==y:
            return True
    return False
def getExportObject(className):
    for x in export:
        if x[0]==className:
            return x
    return None

def prt(s):
    print globalTab+s
def it():
    global globalTab
    if len(globalTab)>0:
        globalTab=globalTab[1:]
def dt():
    global globalTab
    globalTab=globalTab+"\t"
def first_prt(frst):
    if frst:
        return False
    prt(",")
    return True
def w_class(ccc,template,nameAs):
    cc=namespace.parse._Class(ccc["namespace"],ccc["type"],ccc["inner"])
    cc.data=ccc.data.copy()
    if len(cc["templates"])!=0:
        if len(template)<3:
            return False
        template2=template[1:]
        template2=template2[:len(template2)-1]
        tempData=cc["templates"]
        tempData2=template2.split(",")
        final_temp=[]
        if len(tempData)!=len(tempData2):
            return False
        for t in range(0,len(tempData)):
            final_temp.append([tempData[t],tempData2[t]])
        for t in cc.getObjects("Type"):
            if t["isTemplate"]:
                for xt in final_temp:
                    if xt[0]==t["name"]:
                        t["name"]=xt[1]
                        t.update()
        for t in cc.getObjects("Type"):
            t.update()
    bases=""
    for b in cc["base"]:
        if bases!="":
            bases=bases+","
        bases=bases+b[0]
    if bases!="":
        bases=",luabind::bases<"+bases+">"
    cname=cc["namespace"]+"::"+cc["name"]+template
    prt("luabind::class_<"+cname+bases+">(\""+nameAs+"\")")
    dt()
    c=cc["public"]
    for x in c["constructors"]:
        parameters=""
        for p in x["parameters"]:
            if parameters!="":
                parameters=parameters+","
            parameters=parameters+p["type"]["fullname"]
        prt(".def(luabind::constructor<"+parameters+">())")
    for x in c["fields"]:
        policies=""
        if x["type"]["name"]=="std::vector" or x["type"]["name"]=="vector":
            policies=",return_stl_iterator"
        prt(".def_readwrite(\""+x["name"]+"\",&"+cname+"::"+x["name"]+policies+")")
    for x in c["enums"]:
        prt(".enum_("+x["name"]+")")
        prt("[")
        dt()
        for v in x["rows"]:
            prt("luabind::value(\""+v["name"]+"\","+str(v["value"])+")")
        prt("]")
        it()
    for x in c["methods"]:
        params=""
        operParams=""
        for p in x["parameters"]:
            if params!="":
                params=params+","
                operParams=operParams+","
            params=params+p["type"]["fullname"]
            operParams=operParams+"luabind::other<"+p["type"]["name"]+">()"
        if x["isOperator"]==False:
            prt(".def(\""+x["name"]+"\",("+x["returnType"]["fullname"]+"("+cname+"::*)("+params+"))&"+cname+"::"+x["name"]+")")
        else:
            withOper="luabind::self"
            if x["operator"]=="()":
                withOper=withOper+"("+operParams+")"
            else:
                if len(x["parameters"])==0:
                    withOper=x["operator"]+withOper
                else:
                    if x["operator"]=="+" or x["operator"]=="-" or x["operator"]=="*" or x["operator"]=="/" or x["operator"]=="==" or x["operator"]=="<" or x["operator"]=="<=":
                        withOper=withOper+x["operator"]+operParams
                    else:
                        withOper=""
                    #TODO: operator [] = add directly in lua
            if withOper!="":
                prt(".def("+withOper+")")
    if len(c["classes"])!=0:
        w_scope=False
        first=True
        for x in c["classes"]:
            ex_obj=getExportObject(x["namespace"]+"::"+x["name"])
            if ex_obj!=None:
                if w_scope==False:
                    prt(".scope")
                    prt("[")
                    dt()
                if len(x["templates"])==0:
                    first=first_prt(first)
                    w_class(x,"",x["name"])
                for t in ex_obj[1]:
                    first=first_prt(first)
                    w_class(x,"<"+t[0]+">",t[1])
        if w_scope:
            it()
            prt("]")
    it()
def w_function(fn):
    params=""
    for p in fn["parameters"]:
        if params!="":
            params=params+","
        params=params+p["type"]["fullname"]
    prt("luabind::def(\""+fn["name"]+"\",("+fn["returnType"]["fullname"]+"(*)("+params+"))&"+fn["namespace"]+"::"+fn["name"]+")")
    return True
def w_enum(en):
    if getExportObject(en["name"])==None:
        return False
    namespaces=en["namespace"].split("::")
    global_str="luabind::globals(state)"
    for x in namespaces:
        if x!="":
            global_str=global_str+"[\""+x+"\"]"
    for v in en["rows"]:
        prt(global_str+"[\""+v["name"]+"\"]="+str(v["value"])+";")
    return True
def w_namespace(ns):
    using_ns=True
    if ns["name"]!="":
        using_ns=isUsingNamespace(ns["name"])
    if using_ns==False:
        prt("luabind::namespace_(\""+ns["name"]+"\")")
        prt("[")
        dt()
    first=True
    for x in ns["classes"]:
        ex_obj=getExportObject(x["namespace"]+"::"+x["name"])
        if ex_obj!=None:
            if len(x["templates"])==0:
                first=first_prt(first)
                w_class(x,"",x["name"])
            for t in ex_obj[1]:
                first=first_prt(first)
                w_class(x,"<"+t[0]+">",t[1])
    for x in ns["functions"]:
        if getExportObject(x["name"])!=None:    
            first=first_prt(first)
            w_function(x)
    for x in ns["namespaces"]:
        first=first_prt(first)
        w_namespace(x)
    if using_ns==False:
        it()
        prt("]")
readExportObjects()
readUsingNamespace()
prt("class LuaBind")
prt("{")
dt()
prt("static void bind(lua_State *state)")
prt("{")
dt()
prt("luabind::module(state)")
prt("[")
dt()
w_namespace(ns)
it()
prt("];")
it()
for x in ns.getObjects("Enum"):
    w_enum(x)
prt("}")
it()
prt("};")